import 'dart:async';

import 'package:flutter/material.dart';

enum ActionType {
  // 每个浮层放在队列中，先进先出，已支持
  // 内部倒计时结束显示下一个，外部可让用户通过手势点击等关闭浮层
  QUEUE,
  // 后来的浮层直接覆盖前面的
  OVERRIDE,
  // 不覆盖，不显示
  NOT_SHOW,
}

// show 3s
const int SHOW_MAINTAIN_TIME = 3;

// showOrDismiss = true => show
typedef ShowOrDismissCallback(OverlayVO overlay);

final OverlayManagerQueue overlayManagerQueue = OverlayManagerQueue();

class OverlayManagerQueue {
  OverlayManagerQueue._internal();

  static final OverlayManagerQueue _singleton = OverlayManagerQueue._internal();

  factory OverlayManagerQueue() => _singleton;

  List<ShowOrDismissCallback> _listeners = [];

  List<OverlayVO> _overlayQueue = [];

  void addListenShowOrDismiss(ShowOrDismissCallback callback) {
    if (null == callback) return;
    _listeners.add(callback);
  }

  void removeListeners(ShowOrDismissCallback callback) {
    if (_listeners.contains(callback)) {
      _listeners.remove(callback);
    }
  }

  void _notifyShowOrDismiss(OverlayVO vo) {
    _listeners.forEach((element) {
      element?.call(vo);
    });
  }

  void removeListenShowOrDismiss(ShowOrDismissCallback callback) {
    if (null == callback) return;
    if (_listeners.contains(callback)) {
      _listeners.remove(callback);
    }
  }

  // add to queue and check can show
  // return current show
  // id == need show id: means not need to wait
  // return null: add into queue fail
  OverlayVO add2show(OverlayVO vo) {
    if (null == vo || null == vo.content || null == vo.ctx || false == vo.canShow) return null;
    _overlayQueue.add(vo);
    // something already show
    if (_overlayQueue.length > 1) {
      return _overlayQueue.first;
    } else {
      _show(vo);
      return vo;
    }
  }

  bool _show(OverlayVO vo) {
    final overlayState = Overlay.of(vo.ctx);
    if (null != overlayState) {
      overlayState.insert(vo.overlayEntry);
      vo.isShow = true;
      Timer.periodic(Duration(seconds: 1), (timer) {
        if (SHOW_MAINTAIN_TIME == timer.tick) {
          // should dismiss
          _dismiss(vo.id);
          timer?.cancel();
        }
      });
      _notifyShowOrDismiss(vo);
      return true;
    }
    return false;
  }

  bool _dismiss(int overlayId) {
    int index = _overlayQueue?.indexWhere((element) => overlayId == element.id);
    if (index != -1) {
      final ready2dismiss = _overlayQueue[index];
      if (ready2dismiss.isShow) {
        if (true == ready2dismiss.overlayEntry?.mounted) {
          ready2dismiss.overlayEntry?.remove();
          ready2dismiss.isShow = false;
          _overlayQueue.remove(ready2dismiss);
          _notifyShowOrDismiss(ready2dismiss);

          // show next
          if (_overlayQueue.isNotEmpty) {
            _show(_overlayQueue.first);
          }
        }
      }
    }
    return false;
  }

  // dismiss by external user
  void dismiss(int overlayId) {
    _dismiss(overlayId);
  }

  // auto increase
  int _overlayId = 0;

  OverlayVO generateOverlayVO(Widget content, BuildContext ctx) {
    int id = ++_overlayId;
    return OverlayVO(id, content, ctx);
  }

  OverlayVO currentShow() {
    return (null == _overlayQueue || _overlayQueue.isEmpty) ? null : _overlayQueue.first;
  }
}

class OverlayVO {
  bool isShow;
  Widget content;
  BuildContext ctx;
  int id;
  OverlayEntry overlayEntry;

  OverlayVO.internal(this.id, this.content, this.ctx, {this.isShow = false}) {
    overlayEntry = OverlayEntry(
      builder: (context) {
        return this.content;
      },
    );
  }

  factory OverlayVO(int id, Widget content, BuildContext ctx) {
    return OverlayVO.internal(id, content, ctx);
  }

  bool get canShow {
    if (null == ctx) return false;
    final overlayState = Overlay.of(ctx);
    if (null != overlayState) {
      return true;
    }
    return false;
  }

  @override
  String toString() {
    return 'OverlayVO{isShow: $isShow, content: $content, ctx: $ctx, id: $id, overlayEntry: $overlayEntry}';
  }
}
